package com.ideal.frame.sys.service;

import com.google.common.collect.Lists;
import com.ideal.frame.entity.TreeModel;
import com.ideal.frame.jpa.DSLPageRequest;
import com.ideal.frame.jpa.JpaRepositoryImpl;
import com.ideal.frame.sys.entity.QSysMenu;
import com.ideal.frame.sys.entity.QSysRoleMenu;
import com.ideal.frame.sys.entity.SysMenu;
import com.ideal.frame.sys.entity.SysRoleMenu;
import com.ideal.frame.sys.enumerate.MenuType;
import com.ideal.frame.sys.form.search.MenuSearchForm;
import com.ideal.frame.util.DtoUtils;
import com.ideal.frame.util.UserUtils;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.dml.UpdateClause;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: jin
 * @CreateTime: 2019-11-05 14:59
 * @Description: 菜单管理
 */
@Slf4j
@Transactional
@Service
public class SysMenuService {
    @Autowired
    private SysLevelMenuService sysLevelMenuService;
    @PersistenceContext
    protected EntityManager entityManager;

    private JpaRepositoryImpl<SysMenu, Long> menuRepo;
    private JpaRepositoryImpl<SysRoleMenu, Long> roleMenuRepo;
    @Value("${node.level}")
    private int level;

    @PostConstruct
    public void init() {
        this.menuRepo = new JpaRepositoryImpl<>(SysMenu.class, entityManager);
        this.roleMenuRepo = new JpaRepositoryImpl<>(SysRoleMenu.class, entityManager);
    }

    QSysMenu qSysMenu = QSysMenu.sysMenu;
    QSysRoleMenu qSysRoleMenu = QSysRoleMenu.sysRoleMenu;

    /**
     * 获取所有菜单
     *
     * @return
     */
    public List<TreeModel<SysMenu>> getMenuTree() {
        BooleanBuilder where = new BooleanBuilder();
        where.and(qSysMenu.delFlag.eq(false));
        where.and(qSysMenu.id.in(sysLevelMenuService.getLevel(level)));
        List<SysMenu> list = menuRepo.findAll(where);
        list.forEach(t -> t.setLevels(sysLevelMenuService.getMenuLevel(t.getId())));
        return transTo(list);
    }

    /**
     * 获取用户有权限的菜单集合
     *
     * @param userId
     * @return
     */
    @Cacheable(value = "resource", key = "'user'.concat(#userId)", unless = "#result == null || #result.size() == 0")
    public List<SysMenu> getMenuByUser(Long userId) {
        String hql = "from SysMenu m where m.delFlag = 0 " +
                " and exists (select 1 from SysRoleMenu rm" +
                " where rm.sysMenu.id = m.id and exists (select 1 from SysRole r" +
                " where r.id = rm.sysRole.id and r.delFlag = 0 and exists (select 1 from SysUserRole ur" +
                " where ur.sysRole.id = r.id and ur.sysUser.id = ?1)))" +
                " and exists( select 1 from SysLevelMenu lm where lm.level=" + level + " and lm.sysMenu.id = m.id)";
        List<Object> params = new ArrayList<>();
        params.add(userId);

        return menuRepo.selectByHQL(hql, params, SysMenu.class);
    }

    /**
     * 获取用户有权限的菜单树---左侧菜单
     *
     * @param userId
     * @return
     */
    public List<TreeModel<SysMenu>> getMenuTreeByUser(Long userId) {
        List<SysMenu> menus = getMenuByUser(userId);
        List<SysMenu> leftMenu = menus.stream()
                .filter((SysMenu m) -> m.getMenuType().equals(MenuType.MENU.name()))
                .collect(Collectors.toList());
        return transTo(leftMenu);
    }

    /**
     * 获取用户的权限标识集合
     *
     * @param userId
     * @return
     */
    @Transactional
    public List<String> getPermissionByUser(Long userId) {
        List<SysMenu> menus = getMenuByUser(userId);
        List<SysMenu> permissionMenus = menus.stream().filter((SysMenu m) -> StringUtils.isNotEmpty(m.getPermission()))
                .collect(Collectors.toList());
        return Lists.transform(permissionMenus, (SysMenu m) -> m.getPermission());
    }

    private List<TreeModel<SysMenu>> transTo(List<SysMenu> list) {
        List<TreeModel<SysMenu>> menuTree = DtoUtils.toListDto(list, (SysMenu input) -> {
            TreeModel<SysMenu> treeModel = new TreeModel.Builder<SysMenu>()
                    .nodeId(input.getId().toString()).node(input).label(input.getMenuName())
                    .parentId(input.getParentId().toString()).sort(input.getSort())
                    .build();
            return treeModel;
        });
        return DtoUtils.formatTree(menuTree, "0");
    }

    /**
     * 根据id获取菜单信息
     *
     * @param id
     * @return
     */
    public SysMenu getById(Long id) {
        return menuRepo.getOne(id);
    }

    /**
     * 保存菜单信息
     *
     * @param params
     */
    public void save(SysMenu params) {
        if (params.getId() == null) params.setCreateTime(new Date());
        if (params.getParentId() == null) params.setParentId(0L);
        if (params.getSort() == null) params.setSort(0);
        params.setModifyTime(new Date());
        params.setDelFlag(false);
        menuRepo.save(params);
    }

    /**
     * 删除菜单
     * 逻辑删除，级联删除对应子菜单
     *
     * @param ids
     * @return
     */
    public void delete(List<Long> ids) {
        UpdateClause updateClause = menuRepo.updateClause();
        updateClause.set(qSysMenu.delFlag, true);
        updateClause.set(qSysMenu.modifyTime, new Date());
        updateClause.set(qSysMenu.modifyUser, UserUtils.getCurrentUser().getId());
        updateClause.where(qSysMenu.id.in(ids));
        updateClause.execute();
    }
}
